package com.quectel.cms.controller.application;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.google.common.base.Preconditions;
import com.quectel.business.dms.AccessorUtils;
import com.quectel.business.dms.application.ApplicationBusiness;
import com.quectel.business.dms.application.access.Accessor;
import com.quectel.cms.controller.BaseController;
import com.quectel.cms.vo.statistics.DayDeviceNumberVo;
import com.quectel.constant.core.device.DeviceCategoryCodeConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.constant.global.annotation.RequirePermissions;
import com.quectel.core.module.application.dto.ApplicationDto;
import com.quectel.core.module.application.service.ApplicationService;
import com.quectel.core.module.device.dto.DeviceCategoryDto;
import com.quectel.core.module.device.dto.DeviceDto;
import com.quectel.core.module.device.dto.DeviceTypeDto;
import com.quectel.core.module.device.service.DeviceCategoryService;
import com.quectel.core.module.device.service.DeviceService;
import com.quectel.core.module.device.service.DeviceTypeService;
import com.quectel.util.common.DateUtils;
import com.quectel.util.common.Page;
import com.quectel.util.common.Request;
import com.quectel.util.common.Response;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author rananxin
 * @date 2021-11-02 10:59:34
 */
@RestController
@RequestMapping("application")
@Tag(name = "ApplicationController", description = "应用表相关api")
public class ApplicationController extends BaseController {

    @DubboReference
    private ApplicationService applicationService;
    @DubboReference
    private DeviceTypeService deviceTypeService;
    @DubboReference
    private DeviceService deviceService;
    @DubboReference
    private DeviceCategoryService deviceCategoryService;
    @Autowired
    private ApplicationBusiness applicationBusiness;

    @GetMapping("queryMonitorApp")
    @RequirePermissions(values = "application:list")
    @Operation(summary = "查询摄像头应用")
    public Response<List<ApplicationDto>> queryMonitorApp() {
        List<ApplicationDto> result = new ArrayList<>();
        DeviceCategoryDto deviceCategoryDto = deviceCategoryService.selectCacheByCode(DeviceCategoryCodeConstants.INTELLIGENT_MONITOR);
        if (deviceCategoryDto != null) {
            Map<String, Object> params = Request.parseParams(httpServletRequest);
            super.fillAuthorityData(params);
            params.put("deviceCategoryId", deviceCategoryDto.getId());
            result = applicationService.queryList(params);
        }
        return Response.<List<ApplicationDto>>ok().wrap(result);
    }


    @GetMapping("dayDeviceNumber")
    @RequirePermissions(values = "device:list")
    @Operation(summary = "每日设备数统计")
    public Response<DayDeviceNumberVo> dayDeviceNumber(@RequestParam Map<String, Object> params) {

        if (!params.containsKey("startTime") || !params.containsKey("endTime")) {
            return Response.error("error args");
        }
        DateTime startTime = DateUtil.parse(params.get("startTime") + "");
        DateTime endTime = DateUtil.parse(params.get("endTime") + "");

        if (DateUtil.between(startTime, endTime, DateUnit.DAY) > 31) {
            return Response.error("the date is too long");
        }

        super.fillAuthorityData(params);
        int total = deviceService.queryTotal(params);

        int pageNo = 0;
        params.put("limit", 999);
        List<DeviceDto> allDeviceList = new ArrayList<>();
        do {
            params.put("offset", pageNo++ * 999);
            List<DeviceDto> pagedDeviceList = deviceService.queryList(params);
            allDeviceList.addAll(pagedDeviceList);
        } while (total > allDeviceList.size());

        Map<String, List<DeviceDto>> dayGroupDeviceMap = allDeviceList.stream()
                .filter(o -> o.getCreateTime() != null)
                .collect(Collectors.groupingBy(o -> DateUtils.format(o.getCreateTime(), DateUtils.FormatType.SIMPLE)));

        List<String> xData = new ArrayList<>();
        List<Integer> allTotal = new ArrayList<>();
        List<Integer> addTotal = new ArrayList<>();
        int i = 0;

        do {
            String startTimeStr = DateUtils.format(startTime, DateUtils.FormatType.SIMPLE);
            List<DeviceDto> deviceDtos = dayGroupDeviceMap.get(startTimeStr);
            xData.add(startTimeStr);
            int size = deviceDtos == null ? 0 : deviceDtos.size();
            addTotal.add(size);
            i += size;
            allTotal.add(i);
            startTime = DateUtil.offsetDay(startTime, 1);
        } while (endTime.getTime() - startTime.getTime() >= 0);

        DayDeviceNumberVo dayDeviceNumberVo = new DayDeviceNumberVo();
        dayDeviceNumberVo.setXData(xData.stream().toArray(String[]::new));
        DayDeviceNumberVo.DataInfo[] yData = new DayDeviceNumberVo.DataInfo[2];
        yData[0] = new DayDeviceNumberVo.DataInfo("设备总数", allTotal.stream().toArray(Integer[]::new));
        yData[1] = new DayDeviceNumberVo.DataInfo("新增设备数", addTotal.stream().toArray(Integer[]::new));
        dayDeviceNumberVo.setYData(yData);
        return Response.<DayDeviceNumberVo>ok().wrap(dayDeviceNumberVo);
    }

    @PostMapping("syncDevice")
    @RequirePermissions(values = "device:sync")
    @Operation(summary = "设备同步")
    public Response<Object> syncDevice(@RequestBody Long applicationId) {
        ApplicationDto applicationDto = applicationService.selectById(applicationId);
        if (applicationDto == null) {
            return Response.error("null application");
        }

        DeviceTypeDto deviceTypeDto = deviceTypeService.selectById(applicationDto.getDeviceTypeId());

        Accessor baseAccessor = AccessorUtils.getBaseAccessor(deviceTypeDto);
        Preconditions.checkNotNull(baseAccessor);
        baseAccessor.syncOrRegisterDevices(applicationDto, null);
        return Response.ok();
    }

    /**
     * 列表
     */
    @GetMapping("list")
    @RequirePermissions(values = "application:list")
    @Operation(summary = "应用的分页查询列表")
    public Response<Page<ApplicationDto>> list(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize
    ) {
        //查询列表数据
        Request request = Request.configParams(Request.parseParams(httpServletRequest)).like("name");

        super.fillAuthorityData(request.getParams());
        int total = applicationService.queryTotal(request.getParams());

        List<ApplicationDto> list = null;
        if (total > 0) {
            list = applicationService.queryList(request.getParams());
        } else {
            list = new ArrayList<>();
        }

        Page<ApplicationDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, list);
        return Response.<Page<ApplicationDto>>ok().wrap(page);
    }


    /**
     * 信息
     */
    @GetMapping("info/{id}")
    @RequirePermissions(values = "application:info")
    @Operation(summary = "查询单条应用记录")
    public Response<ApplicationDto> info(@PathVariable("id") Long id) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        if (applicationService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        ApplicationDto applicationDto = applicationService.selectById(id);

        return Response.<ApplicationDto>ok().wrap(applicationDto);
    }

    /**
     * 保存
     */
    @PostMapping("save")
    @RequirePermissions(values = "application:edit")
    @Operation(summary = "保存单条应用记录")
    public Response<Object> save(@RequestBody @Validated ApplicationDto applicationDto) {

        //填充基础数据
        fillSaveCommonData(applicationDto);

        Long id = applicationService.save(applicationDto);

        applicationBusiness.init(applicationService.selectById(id), false);

        return Response.ok();
    }

    /**
     * 初始化应用
     */
    @PostMapping("init")
    @RequirePermissions(values = "application:edit")
    @Operation(summary = "批量初始化应用")
    public Response<Object> init(@RequestBody Long[] ids) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);

        for (Long id : ids) {

            params.remove(SystemConstants.ENTITY_ID_FLAG);
            params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));

            if (applicationService.queryTotal(params) <= 0) {
                return Response.error(SystemConstants.ILLEGAL_MSG);
            }
        }

        for (Long id : ids) {
            applicationBusiness.init(applicationService.selectById(id), false);
        }

        return Response.ok();
    }

    /**
     * 修改
     */
    @PostMapping("update")
    @RequirePermissions(values = "application:edit")
    @Operation(summary = "修改单条应用记录")
    public Response<Object> update(@RequestBody @Validated ApplicationDto applicationDto) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(applicationDto.getId()));
        if (applicationService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }
        //填充基础数据
        fillEditCommonData(applicationDto);

        applicationService.updateById(applicationDto);

        applicationBusiness.init(applicationService.selectById(applicationDto.getId()), false);

        return Response.ok();
    }

    /**
     * 删除
     */
    @PostMapping("delete")
    @RequirePermissions(values = "application:delete")
    @Operation(summary = "批量删除存在的应用记录")
    public Response<Object> delete(@RequestBody Long[] ids) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);

        for (Long id : ids) {

            params.remove(SystemConstants.ENTITY_ID_FLAG);
            params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));

            if (applicationService.queryTotal(params) <= 0) {
                return Response.error(SystemConstants.ILLEGAL_MSG);
            }
        }

        applicationService.deleteBatch(ids);

        return Response.ok();
    }
}
